package com.ikas.autumn.iec104.common.handle;

import com.ikas.autumn.iec104.common.baseEntity.JsonResult;
import com.ikas.autumn.iec104.common.enums.JsonResultConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 能拦截抛异常、参数类型异常等情况，404无法拦截
 * @author wu.yunfeng
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler{

    /**出现异常，返回的状态码500*/
    @ExceptionHandler(Exception.class)
    public String exceptionHandler(HttpServletRequest req,Exception e){
        log.info("捕获到异常信息...");
        if(e instanceof MethodArgumentNotValidException){
            MethodArgumentNotValidException exception= (MethodArgumentNotValidException) e;
            return handlerMethodArgumentNotValidException(exception);
        }  else{
            return errorHandler(req, e);
        }
    }

    private String errorHandler(HttpServletRequest req, Exception e) {
        log.error(String.format("Request %s throw exception: %s", req.getRequestURI(), e.getMessage()), e);
        JsonResult result = new JsonResult(JsonResultConstants.INTERNALSERVERERROR);
        String msg = null;
        if (StringUtils.isNotBlank(e.getMessage())) {
            msg = e.getMessage();
        }
        if (StringUtils.isBlank(msg) && e.getCause() != null && StringUtils.isNotBlank(e.getCause().getMessage())) {
            msg = e.getCause().getMessage();
        }
        // 然后提取错误提示信息进行返回
        result.setMessage(msg);
        return result.toJSON();
    }


    /**
     * 捕捉404异常
     * @return
     */
    public String handleNoHandlerFoundException(NoHandlerFoundException e) {
        return JsonResult.error(JsonResultConstants.NOTFOUND, "访问路径出错," + e.getMessage()).toJSON();
    }

    /**
     * 方法参数验证异常处理
     * @param e 方法参数异常
     * @return jsonResult
     */
    public String handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        JsonResult jsonResult = JsonResult.error(JsonResultConstants.BADREQUEST);
        List<String> errors = e.getBindingResult().getFieldErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.toList());
        jsonResult.setMessage(StringUtils.join(errors, ","));
        return jsonResult.toJSON();
    }

    /**
     * 重复记录异常捕获
     * @param e
     * @return
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public String handleDuplicateKeyException(DuplicateKeyException e){
        log.error("数据库中已存在该记录," + e.getMessage(), e);
        return JsonResult.error("数据库中已存在该记录").toJSON();
    }

    /**
     * 处理所有参数校验时抛出的异常
     *
     * @param e 校验异常
     * @return jsonResult
     */
    @ExceptionHandler(value = ValidationException.class)
    public JsonResult handleBindException(ValidationException e) {
        // 获取所有异常
        List<String> errors = new LinkedList<>();
        JsonResult jsonResult = JsonResult.error(JsonResultConstants.BADREQUEST);
        if(e instanceof ConstraintViolationException){
            ConstraintViolationException exs = (ConstraintViolationException) e;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                String message = item.getMessage();
                errors.add(message);
            }
        }
        jsonResult.setMessage(StringUtils.join(errors, ","));
        return jsonResult;
    }

    /**
     * 处理绑定异常
     *
     * @param e 绑定异常
     * @return jsonResult
     */
    @ExceptionHandler(value = BindException.class)
    public JsonResult handleBindException(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        // 获取所有异常
        List<String> errors = new LinkedList<>();
        JsonResult jsonResult = JsonResult.error(JsonResultConstants.BADREQUEST);
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        if (CollectionUtils.isEmpty(allErrors)) {
            jsonResult.setMessage("参数异常");
        } else {
            for (ObjectError error : allErrors) {
                StringBuilder msg = new StringBuilder();
                if (error instanceof FieldError) {
                    msg.append(((FieldError) error).getField()).append(": ");
                }
                String messageKey = error.getDefaultMessage() == null ? "" : error.getDefaultMessage();
                msg.append(messageKey);
                errors.add(msg.toString());
            }
        }
        jsonResult.setMessage(StringUtils.join(errors, ","));
        return jsonResult;
    }



}
